package br.unisul.prolinear.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map.Entry;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.criterion.Restrictions;

import br.unisul.prolinear.utils.FilterList;
import br.unisul.prolinear.utils.FilterValue;
import br.unisul.prolinear.utils.HibernateUtil;

@SuppressWarnings("unchecked")
public class GenericDaoImp<T> implements GenericDao<T> {

	private final Class<T> oClass;

	public GenericDaoImp() {
		this.oClass = (Class<T>)((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@Override
	public Class<T> getObjectClass() {
		return this.oClass;
	}

	@Override
	public T save(T object) {
		HibernateUtil.beginTransaction();
		try{
			Object obj = HibernateUtil.getSession().merge(object);
			HibernateUtil.commitTransaction();
			return (T) obj;
		}catch(HibernateException e){
			HibernateUtil.rollbackTransaction();
			throw e;
		}
	}

	@Override
	public void delete(T object) {
		HibernateUtil.beginTransaction();
		try{
			HibernateUtil.getSession().delete(object);
			HibernateUtil.commitTransaction();
		}catch(HibernateException e){
			HibernateUtil.rollbackTransaction();
			e.printStackTrace();
			throw e;
		}
	}

	@Override
	public List<T> list() {
		List<T> list ;
		try {			
			list = HibernateUtil.getSession().createCriteria(oClass).list();			
			return (List<T>) list;
		} catch (HibernateException hibernateException) {
			throw hibernateException;
		}finally{
			HibernateUtil.closeSession();
		}

	}


	@Override
	public List<T> listFiltered(FilterList filtros) {
		try{
			Criteria crit =  HibernateUtil.getSession().createCriteria(oClass);
			for(Entry<String, FilterValue> filtro :filtros.entrySet()){
				switch(filtro.getValue().getExp()){
				case equal:
					crit.add(Restrictions.eq(filtro.getKey(), filtro.getValue().getValor()));
					break;
				case ne:
					crit.add(Restrictions.ne(filtro.getKey(), filtro.getValue().getValor()));
					break;
				}		
			}
			return (List<T>) crit.list();
		}finally{
			HibernateUtil.closeSession();
		}

	}

	@Override
	public T getById(Serializable id) {
		try {
			Object obj = HibernateUtil.getSession().get(oClass, id);
			return (T) obj;
		} catch (Exception e) {
			e.printStackTrace();
		//	throw e;
			return null;
		}finally{
			HibernateUtil.closeSession();
		}

	}

	@Override
	public T getById(Long id, boolean lock) {
		try {
			if (lock) {
				return (T) HibernateUtil.getSession().get(oClass, id, LockOptions.UPGRADE);
			} else {
				return (T) HibernateUtil.getSession().get(oClass, id);
			}
		} catch (HibernateException hibernateException) {
			throw hibernateException;
		}finally{
			HibernateUtil.closeSession();
		}

	}

	@Override
	public List<T> consultaHQL(String consulta) {
		return (List<T>) HibernateUtil.getSession().createQuery(consulta).list();
	}


	@Override
	public void deleteItem(T object) {
		try{
			HibernateUtil.beginTransaction();
			HibernateUtil.getSession().delete(object);
		}catch(HibernateException e){
			HibernateUtil.rollbackTransaction();
			throw e;
		}
	}

	@Override
	public T get(String campo, Object valor) {
		try{
			List<T> lista =  HibernateUtil.getSession().createCriteria(oClass).add(Restrictions.eq(campo, valor)).list();
			if(lista.isEmpty()){  
				return null;
			} else{
				return (T) lista.get(0);
			}
		}catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		finally{
			HibernateUtil.closeSession();
		}
	}
}
